package nio.c2;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.Iterator;

@Slf4j
public class Server {
    public static void main(String[] args) throws IOException {
        Selector selector = Selector.open();
        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.configureBlocking(false);//设置非阻塞模式
        //把ServerChannel注册到selector监听。
        SelectionKey sscKey = ssc.register(selector, 0, null);
        //设置这个chanle事件监听类型为连接
        sscKey.interestOps(SelectionKey.OP_ACCEPT);
        log.debug("accept...sscKey,{}", sscKey);
        System.out.println("accept...sscKey,{}"+ sscKey);
        ssc.bind(new InetSocketAddress(7077));

        while (true) {
            //监听是否有事件，没有就阻塞
            selector.select();
            //获取管理channel集合的所有key通过迭代器执行后续
            Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
            while (iter.hasNext()){

                SelectionKey key = iter.next();
                // 处理key 时，要从 selectedKeys 集合中删除，否则下次处理就会有问题
                iter.remove();
                log.debug("iter.key:{},",key);
                //区分事件类型
                if (key.isAcceptable()) { //如果是accept连接事件
                    ServerSocketChannel channel =(ServerSocketChannel) key.channel();
                    SocketChannel sc = channel.accept();//客户端连接
                    sc.configureBlocking(false);
                    SelectionKey scKey = sc.register(selector, 0, null);
                    //设置客户端channel监听类型为可读
                    scKey.interestOps(SelectionKey.OP_READ);
                    log.debug("channel{}",sc);
                    log.debug("scKey{}",scKey);
                    System.out.println("channel"+ sc);
                    System.out.println("scKey"+ scKey);
                } else if(key.isReadable()){ //如果是可读事件, 客户端非正常断开连接会监听报错抛异常
                    try {
                        SocketChannel channel =(SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(4);
                        int read = channel.read(buffer); // 如果是正常断开，read 的方法的返回值是 -1
                        if(read == -1 ){
                            //没读到数据就默认不处理事件，取消删除该事件
                            key.cancel();
                        }else{
                            buffer.flip();
//                            log.info("key-read...{}-{}",key,Charset.defaultCharset().decode(buffer));
                            System.out.println(Charset.defaultCharset().decode(buffer));
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                        key.cancel();  // 因为客户端断开了,因此需要将 key 取消（从 selector 的 keys 集合中真正删除 key）
                    }
                }

            }
        }
    }
}
